<html>
  <head>
    <title>实体</title>
  </head>
  <body>
    <script>
      //  实体   最佳实践和约定

            /*
                一、实体  Entities

                      每个聚合根也是一个实体。因此，这些规则对聚合根也有效，除非聚合根规则覆盖它们。


                      在领域层定义实体！！


                      1、主构造函数  Primary Constructor

                              ①、请定义一个主构造函数，以确保实体在创建时的有效性。

                                      主构造函数用于通过应用程序代码创建实体的新实例。

                              ②、根据要求将主构造函数定义为public、internal或protected internal。

                                      如果它不是公开的，则该实体应该由领域服创建。

                              ③、总是在主构造函数中初始化子集合。

                              ④、不要在构造函数中生成Guid键。

                                      将其作为参数获取，因此调用代码将使用IGuidGenerator生成新的Guid值

                      2、无参构造函数 Parameterless Constructor

                               ①、始终定义一个protected无参数构造函数以与ORM兼容。


                      3、引用

                                始终通过ID将引用其他聚合根。切勿以导航属性的方式引用其他聚合根。

                      4、其他类成员

                                ①、始终将方法和属性定义为 virtual （似有的private除外）。因为一些ORM 和代理工具需要它。

                                ②、保持实体在自己的边界内始终有效和一致。

                                        ①、定义属性是，使用private、protected、internal 或protected internal 的setter的定义要保护实体一致性和有效性的属性。

                                        ②、请定义public 、internal或protected internal(virtual）的方法以在必要时更改属性（使用非公共设置器）。

                                        ③、在setter方法中返回 "this" 以实现链式调用
            */


            /*
                二、聚合根  Aggregate Roots


                        1、主键

                                  ①、请始终为聚合根使用Id 

                                  ②、不要将复合主键用于聚合根

                                  ③、使用guid作为聚合根主键

                        2、基类

                                需要从  AggregateRoot<TKey>或 审核聚合根类之一
                                  
                                （CreationAuditedAggregateRoot<TKey>、AuditedAggregateRoot<TKey>或FullAuditedAggregateRoot<TKey>）继承。

                        3、聚合边界

                                要让聚合尽可能小。大多数聚合只有原始属性，不会有子集合。

                                将这些视为设计决策：

                                    性能&内存加载和保存聚合的成本（请记住，聚合通常被加载并保存为单个单元）。

                                    更大的聚合将消耗更多的CPU和内存。

                                    一致性&有效性边界。

            */


            /*
                三、示例


                        1、聚合根

                                  public class Issue : FullAuditedAggregateRoot<Guid> //Using Guid as the key/identifier
                                  {
                                              public virtual string Title { get; private set; } //Changed using the SetTitle() method
                                              public virtual string Text { get; set; } //Can be directly changed. null values are allowed
                                              public virtual Guid? MilestoneId { get; set; } //Reference to another aggregate root
                                              public virtual bool IsClosed { get; private set; } 
                                              public virtual IssueCloseReason? CloseReason { get; private set; } //  属性的setter需要时似有的
                                              public virtual Collection<IssueLabel> Labels { get; protected set; } // 子集合属性的setter要是似有的或受保护的

                                              protected Issue()
                                              {
                                                  // 空构造函数时留给ORM用的
                                              }

                                              //主构造函数，用来给代码创建聚合根实体的
                                              public Issue(
                                                  Guid id, //Get Guid value from the calling code
                                                  [NotNull] string title, //Indicate that the title can not be null.
                                                  string text = null,
                                                  Guid? milestoneId = null) //Optional argument
                                              {
                                                  Id = id;
                                                  Title = Check.NotNullOrWhiteSpace(title, nameof(title)); //Validate
                                                  Text = text;
                                                  MilestoneId = milestoneId;
                                                  
                                                  Labels = new Collection<IssueLabel>(); //Always initialize the collection
                                              }

                                              public virtual Issue SetTitle([NotNull] string title)
                                              {
                                                  Title = Check.NotNullOrWhiteSpace(title, nameof(title)); //Validate
                                                  return this;
                                              }


                                              // 通过公有虚方法来操作子集合属性，而不是通过公有Setter设置属性
                                              public virtual Issue AddLabel(Guid labelId)
                                              {
                                                  if (Labels.Any(l => l.LabelId == labelId))
                                                  {
                                                      return;
                                                  }

                                                  Labels.Add(new IssueLabel(Id, labelId));
                                                  return this;
                                              }

                                              // 公有虚方法操作子集合属性
                                              public virtual Issue RemoveLabel(Guid labelId)
                                              {
                                                  Labels.RemoveAll(l => l.LabelId == labelId);
                                                  return this;
                                              }


                                              // 通过公有虚方法设置属性
                                              public virtual void Close(IssueCloseReason reason)
                                              {
                                                  IsClosed = true;
                                                  CloseReason = reason;
                                              }

                                              // 通过公有需方法设置属性
                                              public virtual void ReOpen()
                                              {
                                                  IsClosed = false;
                                                  CloseReason = null;
                                              }
                                  }


                         2、实体
                                public class IssueLabel : Entity
                                {
                                    public virtual Guid IssueId { get; private set; }
                                    public virtual Guid LabelId { get; private set; }

                                    protected IssueLabel()
                                    {
                                        
                                    }

                                    public IssueLabel(Guid issueId, Guid labelId)
                                    {
                                        IssueId = issueId;
                                        LabelId = labelId;
                                    }
                                }
                                      
            */



    </script>
  </body>
</html>